#include "../include/logger.hpp"
#include <cassert>
#include <chrono>
#include <memory>
#include <thread>
#include <httplib.h>

using namespace easylog;

void test_sync_logger()
{
    logger_builder::ptr llb = std::make_shared<local_logger_builder>();
    llb->build_logger_type(logger_builder::sync);
    llb->build_logger_name("sync_test");
    llb->build_limit_level(level::debug);
    llb->build_sinker<stdout_sinker>();
    logger::ptr lgr = llb->build();
    lgr->info("{}:{}", "test", 1);
    lgr->info("%s:%d", "test", 1);
}

void test_async_logger()
{
    logger_builder::ptr llb = std::make_shared<local_logger_builder>();
    llb->build_logger_type(logger_builder::async);
    llb->build_logger_name("async_test");
    llb->build_limit_level(level::debug);
    llb->build_sinker<stdout_sinker>();
    llb->build_work_type(logger_builder::work_type::safe);
    llb->build_thread_num();
    llb->build_buffer_size();
    llb->build_buffer_increment();
    llb->build_buffer_threshold();
    logger::ptr lgr = llb->build();
    lgr->info("{}:{}", "test", 2);
    lgr->info("%s:%d", "test", 2);
    std::this_thread::sleep_for(std::chrono::seconds(1));
    // On MacOS if we don't wait for asworker finish to sink,
    // then we will see the exception below:
    //   lbc++abi: terminating with uncaught exception of type std::__1::system_error: mutex lock failed: Invalid argument
    //   zsh: abort      ./test_logger
}

void test_global_logger_builder()
{
    logger_builder::ptr glb = std::make_shared<global_logger_builder>();
    glb->build_logger_type(logger_builder::sync);
    glb->build_logger_name("test");
    glb->build_limit_level(level::debug);
    glb->build_sinker<stdout_sinker>();
    glb->build();
    logger::ptr lgr = registry::instance().get("test");
    lgr->info("{}:{}", "test", 1);
    lgr->info("%s:%d", "test", 1);
}

void test_flush()
{
    logger_builder::ptr llb = std::make_shared<local_logger_builder>();
    llb->build_logger_type(logger_builder::async);
    llb->build_logger_name("async_test");
    llb->build_limit_level(level::debug);
    llb->build_sinker<file_sinker>();
    llb->build_work_type(logger_builder::work_type::safe);
    llb->build_thread_num();
    llb->build_buffer_size();
    llb->build_buffer_increment();
    llb->build_buffer_threshold();
    logger::ptr lgr = llb->build();
    lgr->get_sinkers()[0]->set_logfile("log.txt");
    lgr->info("{}:{}", "i get a message", 1);
    std::this_thread::sleep_for(std::chrono::seconds(3));
    lgr->flush();
    std::cout << "flush now" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "quit now" << std::endl;
}

void test_always_flush()
{
    logger_builder::ptr llb = std::make_shared<local_logger_builder>();
    llb->build_logger_type(logger_builder::async);
    llb->build_logger_name("async_test");
    llb->build_limit_level(level::debug);
    llb->build_sinker<file_sinker>();
    llb->build_work_type(logger_builder::work_type::safe);
    llb->build_thread_num();
    llb->build_buffer_size();
    llb->build_buffer_increment();
    llb->build_buffer_threshold();
    logger::ptr lgr = llb->build();
    lgr->get_sinkers()[0]->set_logfile("log.txt");
    lgr->set_always_flush();
    lgr->info("{}:{}", "i get a message", 1);
    std::cout << "log now" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(2));
    std::cout << "quit now" << std::endl;
}

void test_flush_every()
{
    if (0)
    {
        logger_builder::ptr llb = std::make_shared<local_logger_builder>();
        llb->build_logger_type(logger_builder::sync);
        llb->build_logger_name("sync_test");
        llb->build_limit_level(level::debug);
        llb->build_sinker<file_sinker>("log.txt");
        logger::ptr lgr = llb->build();
        lgr->set_flush_every(util::time::time_enum::t2sec);
        int i = 0;
        while (true)
        {
            lgr->info("{}:{}", "test", ++i);
            std::this_thread::sleep_for(std::chrono::milliseconds(500));
        }
    }
    else
    {
        logger_builder::ptr llb = std::make_shared<local_logger_builder>();
        llb->build_logger_type(logger_builder::async);
        llb->build_logger_name("async_test");
        llb->build_limit_level(level::debug);
        llb->build_sinker<file_sinker>("log.txt");
        llb->build_work_type(logger_builder::work_type::safe);
        llb->build_thread_num();
        llb->build_buffer_size();
        llb->build_buffer_increment();
        llb->build_buffer_threshold();
        logger::ptr lgr = llb->build();
        lgr->set_flush_every(util::time::time_enum::t2sec);
        int i = 0;
        while (true)
        {
            lgr->info("{}:{}", "test", ++i);
            httplib::Client("baidu.com").Get("/");
            httplib::Client("baidu.com").Get("/");
            httplib::Client("baidu.com").Get("/");
            httplib::Client("baidu.com").Get("/");
            httplib::Client("baidu.com").Get("/");
            std::this_thread::sleep_for(std::chrono::milliseconds(200));
        }
    }
}

#define TEST \
                6

int main()
{
    switch (TEST)
    {
        case 1: test_sync_logger();  break;
        case 2: test_async_logger(); break;
        case 3: test_global_logger_builder(); break;
        case 4: test_flush(); break;
        case 5: test_always_flush(); break;
        case 6: test_flush_every(); break;
        default: assert(false); break;
    }

    return 0;
}
